public class MaxSum {

    /**
     * 动态规划
     * @param nums
     * @return
     */
    public static int sumDP(int []nums){
        int res=Integer.MAX_VALUE;
        int[]dp=new int[nums.length];
        dp[0]= nums[0];
        res=dp[0];

        for(int i=1;i<nums.length;i++){
            dp[i]= Math.max(nums[i],dp[i-1]+nums[i]);
            res=Math.max(res,dp[i]);
        }
        return res;
    }

    /**
     * 分治法
     * @param nums
     * @return
     */
    public static int maxSubArray(int[] nums) {
        return maxSubArrayHelper(nums, 0, nums.length - 1);
    }
    private static int maxSubArrayHelper(int[] nums, int low, int high) {
        if (low == high) {
            return nums[low];
        }

        int mid = (low + high) / 2;

        // 递归求解左右子序列的最大子序列和
        int leftMax = maxSubArrayHelper(nums, low, mid);
        int rightMax = maxSubArrayHelper(nums, mid + 1, high);

        // 计算跨越左右子序列的最大子序列和
        int maxLeftSuffix = Integer.MIN_VALUE;
        int sumLeft = 0;
        for (int i = mid; i >= low; i--) {
            sumLeft += nums[i];
            maxLeftSuffix = Math.max(maxLeftSuffix, sumLeft);
        }

        // 重复
        int maxRightPrefix = Integer.MIN_VALUE;
        int sumRight = 0;
        for (int i = mid + 1; i <= high; i++) {
            sumRight += nums[i];
            maxRightPrefix = Math.max(maxRightPrefix, sumRight);
        }

        int maxCrossingSum = maxLeftSuffix + maxRightPrefix;

        // 返回三个值中的最大值
        return Math.max(Math.max(leftMax, rightMax), maxCrossingSum);
    }

    /**
     * 最简单模拟
     */

    public static int max1(int [] nums){
        // 特例判断
        if(nums.length==1){
            return nums[0];
        }
        int res=Integer.MIN_VALUE;
        int count=0;
        for(int i=0;i<nums.length;i++){
            count+=nums[i];
            res =Math.max(res,count); // 取区间累计的最大值（相当于不断确定最大子序终止位置）
            if(count<=0){
                count=0; //清0
            }
        }
        return res;
    }

    // 测试函数
    public static void main(String[] args) {
        int []test={1,4,3,2,1,2,4,-1,4,-5,7,3,8,9};

        // 简单直接做法
        int t1=max1(test);
        System.out.println("直接模拟得到的最大子序和："+t1);

        // 动态规划
        int t2=sumDP(test);
        System.out.println("动态规划得到的最大子序和："+t2);

        // 分治法
        int t3=maxSubArray(test);
        System.out.println("分治法得到的最大子序和："+t3);
    }
}
